﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RAP.Framework.Libary.JSON;
using RAP.Framework.Libary.JSON.Conversion;
using RAP.Framework.Libary.Utils;

namespace RAP.Framework.Libary.DataSource.Model.DataSource
{
  /// <summary>
  /// 数据源配置根节点
  /// </summary>
  public class DataSourceConfig
  {
    /// <summary>
    /// 解密SQL连接字符串的密码前缀
    /// </summary>
    public static string CONNECTION_STRING_PASSWORD_PREFIX = "sqlservice@reallyinfo.com.";

    /// <summary>
    /// 数据源驱动配置
    /// </summary>
    public DataSourceProviders Providers { get; set; }

    /// <summary>
    /// 数据源配置集合
    /// </summary>
    public DataSourceOptionCollection DataSources { get; set; }


    /// <summary>
    /// 默认数据源
    /// </summary>
    public string DefaultDataSourceId { get; set; }

    /// <summary>
    /// 是否已初始化
    /// </summary>
    public bool Initialized { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public DataSourceConfig() { }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="d"></param>
    public DataSourceConfig(IDictionary d)
    {
      d.CopyToObject(this, funGetValue: (key, val) =>
      {
        if (key == nameof(Providers))
        {
          return new DataSourceProviders(val as IDictionary);
        }
        else if (key == nameof(DataSources))
        {
          return new DataSourceOptionCollection(val as IDictionary);
        }
        return val;
      });
    }

    /// <summary>
    /// 初始化数据库配置参数
    /// </summary>
    public void Initialize()
    {
      if (Initialized)
      {
        return;
      }
      lock (this)
      {
        if (Initialized)
        {
          return;
        }
        foreach (var dataSourceConfig in DataSources)
        {
          var dataSourceId = dataSourceConfig.Key;
          foreach (var dataSource in dataSourceConfig.Value)
          {
            this.InitDataSourceOption(dataSourceId, dataSource);
          }
        }
        Initialized = true;
      }
    }

    /// <summary>
    /// 初始化数据源配置对象
    /// </summary>
    /// <param name="dataSourceId">数据源Id</param>
    /// <param name="dataSource">数据源配置对象</param>
    /// <exception cref="Exception"></exception>
    public virtual void InitDataSourceOption(string dataSourceId, DataSourceOption dataSource)
    {
      if (dataSource.Initialized)
      {
        return;
      }
      var providerId = dataSource.Provider;

      if (providerId.IsNullOrEmpty())
      {
        throw new Exception($"指定数据源【{dataSourceId}】对应的Provider类型【{providerId}】不存在！");
      }
      var connTypeName = Providers[providerId];
      if (connTypeName.IsNullOrEmpty())
      {
        throw new Exception($"数据源【{dataSourceId}】对应的Provider【{providerId}】不存在！");
      }
      dataSource.DataSourceId = dataSourceId;
      dataSource.ConnectionType = connTypeName;
      dataSource.ConnectionString = DecryptConnectionString(dataSource, dataSourceId);
      if (dataSource.Name.IsNullOrEmpty())
      {
        dataSource.Name = dataSource.DataSourceId;
      }
      dataSource.Initialized = true;
    }
    
    /// <summary>
    /// 添加数据源
    /// </summary>
    /// <param name="dataSourceId">数据源Id</param>
    /// <param name="dataSource">数据源对象</param>
    /// <returns></returns>
    public virtual DataSourceConfig AddDataSource(string dataSourceId, DataSourceOption dataSource)
    {
      this.InitDataSourceOption(dataSourceId, dataSource);
      this.DataSources.Add(dataSourceId, dataSource);
      return this;
    }

    /// <summary>
    /// 解密数据库连接字符串
    /// </summary>
    /// <param name="dataSource">数据源的配置</param>
    /// <param name="dataSourceId">数据源Id</param>
    /// <returns></returns>
    protected virtual string DecryptConnectionString(DataSourceOption dataSource, string dataSourceId)
    {
      if (dataSource.Encrypted)
      {
        var encryptedConnectionString = dataSource.ConnectionString;
        var connectionString = encryptedConnectionString.DESDecrypt2($"{CONNECTION_STRING_PASSWORD_PREFIX}{dataSourceId}");
        dataSource.Encrypted = false;
        dataSource.ConnectionString = connectionString;
        return connectionString;
      }
      else
      {
        return dataSource.ConnectionString;
      }
    }

    ///
    public DataSourceConfig Clone()
    {
      return new DataSourceConfig
      {
        Providers = new DataSourceProviders((IDictionary<string, string>)Providers),
        DataSources = new DataSourceOptionCollection((IDictionary<string, IList<DataSourceOption>>)DataSources),
        DefaultDataSourceId = DefaultDataSourceId
      };
    }
  }
}
